import OSS from 'ali-oss';
import { getOssConfig } from '@/api/index';

/**
 * OSS 配置缓存
 * 避免频繁请求配置接口
 */
let ossConfigCache = null;
let ossConfigExpireTime = 0;

/**
 * 获取 OSS 配置
 * @returns {Promise<Object>} OSS 配置信息
 */
async function getOssConfigData() {
  const now = Date.now();
  
  // 如果缓存有效（30分钟内），直接返回缓存
  if (ossConfigCache && now < ossConfigExpireTime) {
    return ossConfigCache;
  }

  try {
    const res = await getOssConfig();
    
    if (res.code === 2000 && res.data) {
      ossConfigCache = res.data;
      // 设置缓存过期时间为 30 分钟
      ossConfigExpireTime = now + 30 * 60 * 1000;
      return res.data;
    } else {
      throw new Error(res.message || '获取 OSS 配置失败');
    }
  } catch (error) {
    console.error('获取 OSS 配置失败:', error);
    throw error;
  }
}

/**
 * 创建 OSS 客户端
 * @returns {Promise<OSS>} OSS 客户端实例
 */
async function createOssClient() {
  try {
    const config = await getOssConfigData();
    
    // 从 endpoint 中提取 region
    // endpoint 格式: https://oss-cn-hangzhou.aliyuncs.com
    let region = 'oss-cn-hangzhou'; // 默认值
    if (config.endpoint) {
      const match = config.endpoint.match(/oss-([^.]+)/);
      if (match) {
        region = match[0]; // 例如: oss-cn-hangzhou
      }
    }
    
    // 创建 OSS 客户端实例
    const client = new OSS({
      accessKeyId: config.accessKeyId,
      accessKeySecret: config.accessKeySecret,
      region: region,
      bucket: config.bucket,
      // H5 环境需要使用 HTTPS
      secure: true,
      // 使用内网或外网 endpoint（浏览器环境自动使用外网）
      // endpoint: config.endpoint,
    });

    return { client, config };
  } catch (error) {
    console.error('创建 OSS 客户端失败:', error);
    throw error;
  }
}


/**
 * 生成唯一文件名
 * @param {string} originalName - 原始文件名
 * @param {string} prefix - 文件路径前缀，默认为 'uploads/'
 * @returns {string} 生成的唯一文件名
 */
function generateUniqueFileName(originalName, prefix = 'uploads/') {
  const timestamp = Date.now();
  const randomStr = Math.random().toString(36).substring(2, 8);
  
  // 获取文件扩展名
  const ext = originalName.substring(originalName.lastIndexOf('.'));
  
  // 生成文件名：前缀 + 时间戳 + 随机字符串 + 扩展名
  return `${prefix}${timestamp}-${randomStr}${ext}`;
}

/**
 * 上传文件到阿里云 OSS
 * @param {string} filePath - 本地文件路径（uni.chooseImage/chooseVideo 返回的临时路径）
 * @param {Object} options - 上传配置选项
 * @param {string} options.prefix - 文件路径前缀，默认 'uploads/'
 * @param {Function} options.onProgress - 上传进度回调函数
 * @returns {Promise<Object>} 上传结果 { url, name }
 */
export async function uploadToOss(filePath, options = {}) {
  const {
    prefix = 'uploads/',
    onProgress = null,
  } = options;

  try {
    // 获取文件信息
    const fileInfo = await getFileInfo(filePath);
    
    // 生成唯一文件名
    const fileName = generateUniqueFileName(fileInfo.name, prefix);
    
    // 创建 OSS 客户端
    const { client, config } = await createOssClient();

    // #ifdef H5
    // H5 环境：直接使用 File 对象
    const file = await urlToFile(filePath);
    const result = await client.put(fileName, file, {
      progress: onProgress ? (p) => {
        onProgress(Math.floor(p * 100));
      } : undefined,
    });
    // #endif

    // #ifndef H5
    // 小程序环境：使用 multipartUpload
    const result = await client.multipartUpload(fileName, filePath, {
      progress: onProgress ? (p) => {
        onProgress(Math.floor(p * 100));
      } : undefined,
    });
    // #endif

    // 如果有加速域名，使用加速域名替换默认域名
    let fileUrl = result.url;
    if (config.domainName) {
      // 从 result.url 中提取文件路径
      const urlObj = new URL(result.url);
      const filePath = urlObj.pathname;
      // 使用加速域名
      fileUrl = `${config.domainName}${filePath}`;
    }

    // 返回文件的完整 URL
    return {
      url: fileUrl,
      name: result.name,
    };
  } catch (error) {
    console.error('文件上传失败:', error);
    throw error;
  }
}

/**
 * 批量上传文件到阿里云 OSS
 * @param {Array<string>} filePaths - 文件路径数组
 * @param {Object} options - 上传配置选项
 * @param {string} options.prefix - 文件路径前缀
 * @param {Function} options.onProgress - 单个文件上传进度回调 (index, progress)
 * @returns {Promise<Array>} 上传结果数组
 */
export async function uploadMultipleToOss(filePaths, options = {}) {
  const results = [];
  
  for (let i = 0; i < filePaths.length; i++) {
    const filePath = filePaths[i];
    
    try {
      const result = await uploadToOss(filePath, {
        ...options,
        onProgress: options.onProgress ? (progress) => {
          options.onProgress(i, progress);
        } : null,
      });
      
      results.push({
        success: true,
        ...result,
      });
    } catch (error) {
      results.push({
        success: false,
        error: error.message,
        filePath,
      });
    }
  }
  
  return results;
}

/**
 * 获取文件信息
 * @param {string} filePath - 文件路径
 * @returns {Promise<Object>} 文件信息
 */
function getFileInfo(filePath) {
  return new Promise((resolve, reject) => {
    // #ifdef H5
    // H5 环境从路径中提取文件名
    const name = filePath.substring(filePath.lastIndexOf('/') + 1);
    resolve({ name });
    // #endif

    // #ifndef H5
    // 小程序环境使用 getFileInfo
    uni.getFileInfo({
      filePath,
      success: (res) => {
        const name = filePath.substring(filePath.lastIndexOf('/') + 1);
        resolve({
          name,
          size: res.size,
        });
      },
      fail: reject,
    });
    // #endif
  });
}

/**
 * H5 环境：将 URL 转换为 File 对象
 * @param {string} url - 文件 URL
 * @returns {Promise<File>} File 对象
 */
// #ifdef H5
async function urlToFile(url) {
  const response = await fetch(url);
  const blob = await response.blob();
  const fileName = url.substring(url.lastIndexOf('/') + 1);
  return new File([blob], fileName, { type: blob.type });
}
// #endif

/**
 * 清除 OSS 配置缓存
 * 用于配置更新后强制重新获取
 */
export function clearOssConfigCache() {
  ossConfigCache = null;
  ossConfigExpireTime = 0;
}

export default {
  uploadToOss,
  uploadMultipleToOss,
  clearOssConfigCache,
};

